﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml;
using System.Xml.XPath;
using System.Threading;

namespace ShumaDaf
{
    static class MMovies
    {
        static string myName = ".Shuid&Rate";
        public static string permanentCollectionPath = @"Res\Collection.xml";

        public static void scanDirectory(List<string> dirs)
        {
           
            if (!Directory.Exists("Res")) Directory.CreateDirectory("Res");
            XMLFilesEnumerable xfiles = new XMLFilesEnumerable(dirs);
            XmlDocument xd = new XmlDocument();
            XmlElement record = xd.CreateElement("Collection");
            xd.AppendChild(record);

            foreach (FileInfo f in xfiles)
                MMovies.readXML(xd, f);
            // теперь начинаем объединение коллекций, рефрешим старую на основании  новой
            // обновление из новой коллекции  идет если: нет флага отложеной записи и найдена запись по shuid  иначе происходит простое добавление
            XmlDocument xcol = new XmlDocument();
            if (File.Exists(MMovies.permanentCollectionPath)) xcol.Load(MMovies.permanentCollectionPath);
            XmlNode main_col = xcol.SelectSingleNode("Collection");

            if (main_col == null)
            {
                main_col = xcol.CreateElement("Collection");
                xcol.AppendChild(main_col);
            }

            // всю страую коллекцию переведем в оффлайн, вновь отсканеные записи сами отрисуются
            foreach (XmlNode xn in xcol.SelectNodes("Collection/CollectionRecord"))
            {
                XmlNode status = xn.SelectSingleNode("DiskStatus");
                if (status != null) status.FirstChild.Value = "offline";
            }

            foreach (XmlNode xn in xd.SelectNodes("Collection/CollectionRecord"))
            {
                MMovies.addChildren(xd, xn, "DiskStatus", "online"); //только что отсканенные -  конечно же online
                string shuid = xn.Attributes["Shuid"].Value;
                string search = String.Format("/Collection/CollectionRecord[@Shuid='{0}']", shuid);
                XmlNodeList xnList = xcol.SelectNodes(search);
                XmlNode newnode = xcol.ImportNode(xn, true);
                bool canAppend = true;
                for (int i = 0; i < xnList.Count; i++)
                {
                    XmlNode xdeleted = xnList[i];
                    XmlNode flagDelay = xdeleted.SelectSingleNode("OperationComment/DelayedUpdate");
                    if (flagDelay != null)
                    {
                        XmlNode com = xdeleted.SelectSingleNode("OperationComment");
                        com.FirstChild.Value = "Update not allowed, delayed save detected!";
                        canAppend = false;
                        break;
                    }
                    xdeleted.ParentNode.RemoveChild(xdeleted);
                }
                if (canAppend)
                {
                    main_col.AppendChild(newnode);
                }
            }
            xcol.Save(MMovies.permanentCollectionPath);
        }


        /// <summary>
        /// Для текущего каталога функция вернет пользовательские оценки. Если они не заданы и не созданы, то 
        /// функция заполнить их нулями, создав соответсвующие текстовые поля
        /// </summary>
        /// <param name="xmldoc"></param>
        /// <param name="fi"></param>
        /// <returns></returns>
        private static XmlNode getUserRateAndData(FileInfo fi)
        {
            
            string dir = Path.GetDirectoryName(fi.FullName);
            string fname = Path.Combine(dir, myName);
            if (!File.Exists(fname)) getShuid(fi);

            XmlDocument xmldoc = new XmlDocument();
            xmldoc.Load(fname);

            XmlNode ratings = xmldoc.SelectSingleNode("Ratings");
            if (ratings == null) {
                ratings = xmldoc.CreateElement("Ratings");
                xmldoc.AppendChild(ratings);
            }
            
            string[] tags = { "UserRate", "Hrez", "SoundRate", "PicRate", "OrigSound", "OrigSub" };

            foreach (string s in tags)
            {
                if (ratings.SelectSingleNode(s) == null)
                {
                    XmlElement x1 = xmldoc.CreateElement(s);
                    XmlText xt1 = xmldoc.CreateTextNode("0");
                    ratings.AppendChild(x1);
                    ratings.LastChild.AppendChild(xt1);
                }
            }
            xmldoc.Save(fname);

            return ratings;
        }

        /// <summary>
        /// Данная функцие вернет мой идентификатор из директории или сгенерирует новый,  если его там нет.
        /// В случае генерирования нового GUID 
        /// </summary>
        /// <param name="fi"></param>
        /// <returns></returns>
        private static Guid getShuid(FileInfo fi)
        {
            Guid g = new Guid();
            string dir = Path.GetDirectoryName(fi.FullName);
            string fname = Path.Combine(dir, myName);
            XmlDocument xd = new XmlDocument();

            try
            {
                xd.Load(fname);
            }
            catch (Exception) { }
            XmlNode root = xd.SelectSingleNode("Ratings");
            if (root == null)
            {
                root = xd.AppendChild(xd.CreateElement("Ratings"));
            }

            XmlNode shuid = root.SelectSingleNode("Shuid");
            if (shuid==null) {
                shuid=root.AppendChild(xd.CreateElement("Shuid"));
                root.LastChild.AppendChild(xd.CreateTextNode(Guid.NewGuid().ToString()));
            }
            g = Guid.Parse(shuid.LastChild.Value);
            xd.Save(fname);
            return g;
        }

        public static void readXML(XmlDocument xmldoc, FileInfo fi)
        {
            XmlElement record = xmldoc.CreateElement("CollectionRecord");
            Guid g = getShuid(fi);
            record.SetAttribute("Shuid", g.ToString());

            //Add the node to the document.
            xmldoc.FirstChild.AppendChild(record);

            FileStream stream = new FileStream(fi.FullName, FileMode.Open);
            XPathDocument document = new XPathDocument(stream);
            XPathNavigator navigator = document.CreateNavigator();

            string[] tagarray = { "LocalTitle", "Country", "ProductionYear", "OriginalTitle", "CollectionNumber", "Added", "RunningTime", "IMDB" };

            if (navigator.HasChildren)
            {
                foreach (string tag in tagarray) {
                    navigator.MoveToRoot();
                    navigator.MoveToFollowing("Title", "");
                    bool r = navigator.MoveToChild(tag, "");

                    // custom handler <Added>12/1/2010 10:24:45 PM</Added>  -> 2010-12-01
                    if (tag.Contains("Added"))
                    {
                        string s = navigator.Value;
                        string[] s1=s.Split(' ');
                        string[] s2 = s1[0].Split('/');
                        
                        addChildren(xmldoc, record, tag, String.Format("{0}/{1:00}/{2:00}", s2[2],Convert.ToDecimal(s2[0]),Convert.ToDecimal(s2[1])));
                        continue;
                    }

                    if (r)
                        addChildren(xmldoc, record, tag, navigator.Value);
                }
                //director
                navigator.MoveToRoot(); navigator.MoveToFollowing("Title", "");
                XPathExpression exp = XPathExpression.Compile("Persons/Person[@Type=2]/Name");
                XPathNavigator nn=navigator.SelectSingleNode(exp);
                if (nn != null)
                {
                    addChildren(xmldoc, record, "Director", nn.Value);
                }
                //---------------------------------
                navigator.MoveToRoot();
                nn = navigator.SelectSingleNode("Title/Persons");
                XmlElement x = xmldoc.CreateElement("Artists");
                x.InnerXml=nn.InnerXml;
                record.AppendChild(x);

                //---------------------------------
                navigator.MoveToRoot();
                nn = navigator.SelectSingleNode("Title/MediaInfo");
                if (nn != null)
                {
                    x = xmldoc.CreateElement("MediaInfo");
                    try
                    {

                        x.InnerXml = nn.InnerXml;
                        record.AppendChild(x);
                    } catch (Exception) {}
                }

                stream.Close();
            }
            
            //add my fields
            string path = Path.GetDirectoryName(fi.FullName);
            addChildren(xmldoc, record, "Path", path);
            addChildren(xmldoc, record, "Size", FileUtilites.getFolderSize(path).ToString());
            addChildren(xmldoc, record, "ScanDateTime", (DateTime.Now).ToString());
            XmlNode Ratings = getUserRateAndData(fi);

            record.AppendChild(xmldoc.ImportNode(Ratings, true));
        }

        public static void addChildren(XmlDocument xmldoc, XmlNode parentNode, string ChildrenName, string ChildrenTextValue)
        {
            XmlElement x4 = xmldoc.CreateElement(ChildrenName);
            XmlText xt4 = xmldoc.CreateTextNode(ChildrenTextValue);
            parentNode.AppendChild(x4);
            parentNode.LastChild.AppendChild(xt4);
        }
        /// <summary>
        /// сохраним оценки в общем XML файле, а потом сохраним измененные оценки в персональных файлах в папках
        /// </summary>
        /// <param name="xmldoc"></param>
        public static void saveXML(XmlDocument xmldoc, MainWindow win)
        {
            if (xmldoc == null) return;
            XmlNodeList xlist = xmldoc.SelectNodes("Collection/CollectionRecord");
            if (xlist == null) return;
            foreach (XmlNode xn in xlist)
            {
                string shuid = xn.Attributes[0].Value;
                XmlNode xpath = xn.SelectSingleNode("Path");
                if (xpath == null)
                {
                    continue;
                }
                XmlNode modifiedFlag = xn.SelectSingleNode("Modified");
                if ( modifiedFlag == null)
                {
                    continue;
                }
                modifiedFlag.ParentNode.RemoveChild(modifiedFlag); // Чтобы не попало в результирующий XML
                win.ShowMessage("Write "+xpath.FirstChild.Value);
                string path = xpath.FirstChild.Value;

                XmlNode comment = xn.SelectSingleNode("OperationComment");
                if (comment == null )
                    comment=xn.AppendChild(xmldoc.CreateElement("OperationComment"));
                comment.RemoveAll();
                if (!Directory.Exists(path))
                {
                    xn.LastChild.AppendChild(xmldoc.CreateTextNode("Offline, Rating will be save later..."));
                    comment.AppendChild(xmldoc.CreateElement("DelayedUpdate"));
                    continue;
                }

                XmlNode rating = xn.SelectSingleNode("Ratings");
                //rating.AppendChild(xmldoc.CreateElement("Shuid"));
                //rating.LastChild.AppendChild(xmldoc.CreateTextNode(shuid));
                XmlTextWriter tr = new XmlTextWriter(Path.Combine(path, myName), Encoding.UTF8);
                rating.WriteTo(tr);
                tr.Close();
                comment.AppendChild(xmldoc.CreateTextNode("Rating successfuly saved!"));
            }

            StreamWriter xStream = new StreamWriter(Path.Combine(Directory.GetCurrentDirectory(), permanentCollectionPath));
            xmldoc.Save(xStream);
            xStream.Close();

        }
    }
}
